Skip to content

Fix managed MySQL multisite PHPUnit composition#2107

Merged
chubes4 merged 6 commits into
mainfrom
fix-2056-managed-multisite-composition
Jul 26, 2026
Merged

Fix managed MySQL multisite PHPUnit composition#2107
chubes4 merged 6 commits into
mainfrom
fix-2056-managed-multisite-composition

Conversation

@chubes4

@chubes4 chubes4 commented Jul 26, 2026

Copy link
Copy Markdown
Collaborator

Summary

  • preinstall managed MySQL multisite through wp-phpunit's canonical includes/install.php path before the PHPUnit process boots WordPress with network constants
  • materialize declared extra-plugin sources into WP_PLUGIN_DIR, defer requested dependency activation until the network exists, and preserve declared activation order
  • add real disposable MySQL coverage for all standard network tables, network reads/writes, staged dependency presence and activation, and nonzero test/assertion execution

Fixes #2056.

Root cause

Managed PHPUnit previously defined MULTISITE and current-network constants before requiring wp-phpunit's installer in the same PHP process. WordPress therefore entered multisite bootstrap while wptests_blogs and wptests_sitemeta did not exist yet. The installer could not reach its canonical install_network() / populate_network() phase from a valid bootstrap state.

Recipe extra plugins were registered as runtime mounts, but Playground child executions require host inputs to be materialized into VFS. Extra-plugin mounts were omitted from the existing staged-input materialization pass, so declared local validation dependencies could be absent from /wordpress/wp-content/plugins/<slug>. Setup also attempted requested activation before the managed network install.

The Homeboy adapter already supplies the required shape: ordered extra_plugins entries with source, slug, and activate, plus matching dependencyMounts. No adapter change or WP Codebox workaround for an adapter defect is needed.

Lifecycle fix

  1. Validate and prepare each extra-plugin source using the existing recipe source and entrypoint contracts.
  2. Include prepared extra-plugin mounts in Playground staged-input materialization so each source exists at /wordpress/wp-content/plugins/<slug> in child PHP executions.
  3. For managed MySQL multisite only, defer setup-time plugin activation.
  4. Run a separate preinstall PHP invocation through wp-phpunit includes/install.php with run_ms_tests, the managed MySQL credentials, and the wptests_ prefix, but without MULTISITE or current-network constants.
  5. Let wp-phpunit/Core call wp_install(), install_network(), and populate_network() to create and seed blogs, blogmeta, site, sitemeta, registration_log, and signups.
  6. Start the normal managed PHPUnit invocation, now with network constants and an installed schema.
  7. Load dependencies in declared order and activate only entries whose recipe metadata requests activation, before activating the component under test and replaying deferred lifecycle hooks.

Single-site, SQLite, project/external bootstrap, and native database paths do not enter the new preinstall/deferred-activation branch.

Path and threat analysis

  • host sources still pass existing local-source resolution, source-subpath containment, source type, slug, and readable plugin-entrypoint validation before runtime creation
  • sandbox targets are derived from validated plugin slugs, not caller-provided arbitrary destinations
  • managed dependency loading now requires a canonical path exactly one directory beneath WP_PLUGIN_DIR
  • realpath() must resolve to a directory whose parent is the real plugin root, rejecting traversal, nested paths, missing sources, and symlink escapes
  • a readable top-level PHP file with a WordPress Plugin Name header is required; malformed dependency metadata fails closed
  • activation intent is serialized from the recipe rather than inferred from filesystem contents, and input order is preserved

Tests and evidence

  • npm run build
  • npx tsx tests/phpunit-project-autoload.test.ts
  • npx tsx tests/recipe-runtime-setup-staged-materialization.test.ts
  • npm run smoke -- --group=package
  • package smoke passed build, runtime service, external MySQL contract, native MariaDB contract, and lifecycle cleanup tests
  • the Docker-backed test:disposable-mysql-mysqli-e2e was invoked locally but skipped because Docker is unavailable on the authoring host; CI should execute it with Docker

The disposable MySQL regression now asserts:

  • real mysqli connectivity
  • all six canonical multisite network tables exist
  • seeded blog/network rows are readable
  • update_network_option() / get_network_option() round-trip
  • a declared local dependency directory and entrypoint exist under WP_PLUGIN_DIR
  • that dependency is network-active and its activation hook ran after network installation
  • the diagnostic records nonzero tests and assertions with zero failures/errors

Consumer rerun

For Extra-Chill/extrachill-events#355, rerun the existing Homeboy review test with WP_CODEBOX_SOURCE_REF=fix-2056-managed-multisite-composition (or commit f5bca517) while retaining:

{
  "database_type": "mysql",
  "wp_codebox_multisite": true,
  "wp_codebox_phpunit_bootstrap_mode": "managed",
  "validation_dependencies": [
    "<checkout>/.ci/data-machine",
    "<checkout>/.ci/data-machine-events"
  ]
}

Expected startup evidence is no missing wptests_blogs/wptests_sitemeta errors, both dependency directories present under WP_PLUGIN_DIR, requested dependencies network-active, and the consumer's real multisite groups executing against the seeded network schema. After merge, rerun against WP_CODEBOX_SOURCE_REF=main for final consumer evidence.

@chubes4

chubes4 commented Jul 26, 2026

Copy link
Copy Markdown
Collaborator Author

Review blockers resolved in new commits through ca9dee5 (no amend): effective PHPUnit semantics now drive scoped dependency deferral; canonical preinstall excludes recipe-active, MU, and Composer loading; managed bootstrap reuses the seeded network schema; exact validated pluginFile/loadAs metadata controls dependency loading; and activated_plugin now receives Core's two-argument signature. Both contract runs and both workflow-lint runs are green, including the Docker-backed managed MySQL multisite E2E with MU/Composer guards and nonzero test/assertion evidence.

@chubes4
chubes4 merged commit c2caf9a into main Jul 26, 2026
4 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Managed MySQL PHPUnit multisite omits network tables

1 participant